package org.openzip.openzip.archiving.logic;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Collection;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;

class OpenZipArchiver implements IOpenZipArchiver {

	private final String[] extractingClasses = new String[] {
		"org/openzip/openzip/unpacking/controller/UnpackerController.class",
		
		"org/openzip/openzip/unpacking/model/IOpenZipUnpacker.class",
		"org/openzip/openzip/unpacking/model/OpenZipUnpacker.class",
		
		"org/openzip/openzip/unpacking/view/IUnpackerUI.class",
		
		"org/openzip/openzip/unpacking/view/swing/UnpackerGUI.class",
		"org/openzip/openzip/unpacking/view/swing/UnpackerGUI$FileActionListener.class",
		"org/openzip/openzip/unpacking/view/swing/UnpackerGUI$1.class",
		
		"org/openzip/openzip/gui/util/CheckboxedTree.class",
		"org/openzip/openzip/gui/util/CheckboxedTree$1.class",
		"org/openzip/openzip/gui/util/CheckboxedTree$FileTreeNodeCellRenderer.class",
		"org/openzip/openzip/gui/util/CheckboxedTree$FileTreeNodeMouseListener.class",
		"org/openzip/openzip/gui/util/CheckboxedTree$SelfSelectionListener.class",
		"org/openzip/openzip/gui/util/FileCheckBox.class",
		"org/openzip/openzip/gui/util/FileTreeNode.class",
		"org/openzip/openzip/gui/util/FileTreeNode$FileEnumeration.class",
		"org/openzip/openzip/gui/util/ObserverThreestateCheckBox.class",
		"org/openzip/openzip/gui/util/ObserverThreestateCheckBox$ActionListenerPool.class",
		"org/openzip/openzip/gui/util/ObserverThreestateCheckBox$CheckBoxListener.class",
		"org/openzip/openzip/gui/util/State.class",
		"org/openzip/openzip/gui/util/ThreestateCheckBox.class",
		"org/openzip/openzip/gui/util/ThreestateCheckBox$OurButtonModel.class",
		"org/openzip/openzip/gui/util/ThreestateCheckBox$ThreestateAction.class",
		"org/openzip/openzip/gui/util/ThreestateCheckBox$ThreestateCheckBoxTest$1.class",
		"org/openzip/openzip/gui/util/ThreestateCheckBox$ThreestateCheckBoxTest.class",
		"org/openzip/openzip/gui/util/ThreestateCheckBox$ThreestateMouseListener.class",
		
		"org/openzip/openzip/gui/util/layout/StandardForm.class",
		
		"org/openzip/openzip/gui/util/event/ButtonStateChangedListener.class",
		"org/openzip/openzip/gui/util/event/TreeCheckSelectionListener.class",
		
		"org/openzip/openzip/archiving/logic/SelectedFilesModel.class",
		"org/openzip/openzip/archiving/logic/IObservable.class",
		
		"org/openzip/openzip/unpacking/Start.class",


	};

	@Override
	public void makeArchive(File path, Collection<File> files) {
		System.out.println("Cesta: " + path.getAbsolutePath());
		
		makeJarArchive(path, files);
		
		//Here should be prompt for overwriting existing file
		//path.exists()
		if (path.canWrite()) {
			System.out.println("making archive");
			
			makeJarArchive(path, files);
		}
		
	}

	private void makeJarArchive(File path, Collection<File> files) {
		try {
			byte buf[] = new byte[1024];
			// Open archive file
			// Output stream is for writing to the file
			FileOutputStream stream = new FileOutputStream(path.getPath());

			// Construct a string version of a manifest
			StringBuffer sbuf = new StringBuffer();
			sbuf.append("Manifest-Version: 1.0\n");
			sbuf.append("Main-Class: org.openzip.openzip." +
					"unpacking.controller.UnpackerController\n");

			// Convert the string to a input stream
			InputStream is = new ByteArrayInputStream(sbuf.toString().getBytes(
					"UTF-8"));

			// Create archive with manifest
			JarOutputStream jarOut = 
				new JarOutputStream(stream, new Manifest(is));

			// Add unpacking GUI
			addExtractingClasses(jarOut);

			for (File f : files) {
				// Create archive entry
				JarEntry jarEntry = new JarEntry("data/" + f.getName());
				jarEntry.setTime(f.lastModified());
				jarOut.putNextEntry(jarEntry);

				// Write file to archive
				// Input Stream is for reading from the file
				FileInputStream in = new FileInputStream(f.getPath());

				// Transfer bytes from the file to the ZIP file
				int len;
				while ((len = in.read(buf)) > 0) {
					jarOut.write(buf, 0, len);
				}

				// Complete the entry
				jarOut.closeEntry();
				in.close();
			}

			jarOut.close();
			stream.close();

		} catch (Exception ex) {
			ex.printStackTrace();
			System.out.println("Error: " + ex.getMessage());
		}

	}

	private void addExtractingClasses(JarOutputStream out) {
		try {
			byte buf[] = new byte[1024];

			// tohle nacte jar file ve kterem se potom da listovat
			// protoze to ale eclipse nespousti z jaru pouziju kolekci
			/*
			 * String jarFileName = OpenZipArchiver.class.getProtectionDomain()
			 * .getCodeSource().getLocation().getFile(); JarFile jarFile = new
			 * JarFile(jarFileName);
			 */
			
			String jarFileName = OpenZipArchiver.class.getProtectionDomain()
			 		.getCodeSource().getLocation().getFile(); 
			
			JarFile jarFile = new JarFile(jarFileName);
			Enumeration entries = jarFile.entries();
			
			while (entries.hasMoreElements()) {
				// New archive entry(file/directory inside JAR)
				JarEntry jarEntry = (JarEntry)entries.nextElement();
				System.out.println("JAR Entry: " + jarEntry.getName());
				
				// We want to filter-out manifest file since it's being 
				// generated earlier in the code
				if (jarEntry.getName().equalsIgnoreCase(
						"META-INF/MANIFEST.MF")) {
					continue;
				}
				out.putNextEntry(jarEntry);
				
				

				InputStream in = OpenZipArchiver.class
						.getResourceAsStream("/" + jarEntry.getName());
				
				// Transfer bytes from the file to the ZIP file
				int len;
				while ((len = in.read(buf)) > 0) {
					out.write(buf, 0, len);
				}
				
				// Complete the entry
				out.closeEntry();
				in.close();
			}


//			for (int i = 0; i < extractingClasses.length; i++) {
//
//				// New archive entry(file/directory inside JAR)
//				JarEntry jarEntry = new JarEntry(extractingClasses[i]);
//				System.out.println("JAR Entry: " + jarEntry.getName());
//				out.putNextEntry(jarEntry);
//
//				// Add UI
//				
//				//FILESYSTEM - for .class file being copied from filesystem
////				File file = new File("bin/" + extractingClasses[i]);
////				System.out.println("Exists: " + file.exists());
////				System.out.println("Path: " + file.getAbsolutePath());
////				System.out.println("Path: " + file.getPath());
////				
////				InputStream in = new FileInputStream(file.getAbsolutePath());
//				
//				//JAR - .class files are being copied from within JAR
//				String name = "/" + extractingClasses[i];
//				System.out.println(name);
//				
//				InputStream in = OpenZipArchiver.class
//						.getResourceAsStream(name);
//
//				
//
//				
//				// Transfer bytes from the file to the ZIP file
//				int len;
//				while ((len = in.read(buf)) > 0) {
//					out.write(buf, 0, len);
//				}
//				
//				// Complete the entry
//				out.closeEntry();
//				in.close();
//			}
			
		} catch (Exception ex) {
			ex.printStackTrace();
			System.out.println("Error: " + ex.getMessage());
		}

	}
}
